#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
EMS Web资源嵌入脚本
用途: 将构建后的Web静态文件转换为C++头文件，供嵌入式HTTP服务器使用
"""

import os
import sys
import json
import mimetypes
from pathlib import Path
from typing import Dict, List, Tuple

def get_mime_type(file_path: str) -> str:
    """获取文件的MIME类型"""
    mime_type, _ = mimetypes.guess_type(file_path)
    if mime_type is None:
        ext = Path(file_path).suffix.lower()
        mime_map = {
            '.js': 'application/javascript',
            '.css': 'text/css',
            '.html': 'text/html',
            '.json': 'application/json',
            '.svg': 'image/svg+xml',
            '.ico': 'image/x-icon',
            '.woff': 'font/woff',
            '.woff2': 'font/woff2',
            '.ttf': 'font/ttf',
            '.eot': 'application/vnd.ms-fontobject'
        }
        mime_type = mime_map.get(ext, 'application/octet-stream')
    return mime_type

def should_compress(file_path: str) -> bool:
    """判断文件是否应该压缩"""
    ext = Path(file_path).suffix.lower()
    # 这些文件类型通常可以从gzip压缩中受益
    compressible_types = {'.html', '.css', '.js', '.json', '.svg', '.xml', '.txt'}
    return ext in compressible_types

def bytes_to_cpp_array(data: bytes, var_name: str) -> str:
    """将字节数据转换为C++字节数组"""
    lines = []
    lines.append(f"static const unsigned char {var_name}[] = {{")
    
    # 每行16个字节
    for i in range(0, len(data), 16):
        chunk = data[i:i+16]
        hex_values = [f"0x{b:02x}" for b in chunk]
        line = "    " + ", ".join(hex_values)
        if i + 16 < len(data):
            line += ","
        lines.append(line)
    
    lines.append("};")
    lines.append(f"static const size_t {var_name}_size = {len(data)};")
    return "\n".join(lines)

def generate_resource_entry(file_path: str, data: bytes, route: str) -> Tuple[str, str, str]:
    """生成单个资源的C++代码"""
    # 生成变量名 (将特殊字符替换为下划线)
    var_name = "resource_" + "".join(c if c.isalnum() else "_" for c in route.lstrip('/'))
    if var_name.endswith('_'):
        var_name = var_name[:-1]
    if var_name == "resource_" or var_name == "resource":
        var_name = "resource_index"
    
    # 生成字节数组
    array_code = bytes_to_cpp_array(data, var_name)
    
    # 获取MIME类型
    mime_type = get_mime_type(file_path)
    
    # 生成资源条目
    entry_code = f'    {{"{route}", {var_name}, {var_name}_size, "{mime_type}"}}'
    
    return var_name, array_code, entry_code

def scan_web_directory(web_dir: str) -> List[Tuple[str, str, str]]:
    """扫描Web目录并返回文件列表"""
    web_path = Path(web_dir)
    if not web_path.exists():
        raise FileNotFoundError(f"Web目录不存在: {web_dir}")
    
    files = []
    for file_path in web_path.rglob('*'):
        if file_path.is_file():
            # 计算相对路径作为路由
            rel_path = file_path.relative_to(web_path)
            route = '/' + str(rel_path).replace('\\', '/')
            
            # 特殊处理index.html
            if rel_path.name == 'index.html':
                # 添加目录路由
                if str(rel_path) == 'index.html':
                    files.append((str(file_path), route, '/'))
                else:
                    dir_route = '/' + str(rel_path.parent).replace('\\', '/') + '/'
                    files.append((str(file_path), route, dir_route))
            
            files.append((str(file_path), route, route))
    
    # 去重并排序
    unique_files = {}
    for file_path, route, final_route in files:
        if final_route not in unique_files:
            unique_files[final_route] = (file_path, route)
    
    return [(file_path, route, final_route) for final_route, (file_path, route) in unique_files.items()]

def generate_header_file(web_dir: str, output_file: str):
    """生成嵌入式资源头文件"""
    print(f"扫描Web目录: {web_dir}")
    files = scan_web_directory(web_dir)
    
    if not files:
        print("警告: 未找到任何Web文件")
        return
    
    print(f"找到 {len(files)} 个文件")
    
    # 生成头文件内容
    header_lines = [
        "/**",
        " * EMS嵌入式Web资源",
        " * 自动生成的文件，请勿手动编辑",
        f" * 生成时间: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
        " */",
        "",
        "#ifndef EMBEDDED_WEB_RESOURCES_H",
        "#define EMBEDDED_WEB_RESOURCES_H",
        "",
        "#include <string>",
        "#include <unordered_map>",
        "#include <vector>",
        "",
        "namespace ems {",
        "namespace web {",
        "",
        "// 嵌入式Web资源结构",
        "struct EmbeddedResource {",
        "    const char* path;",
        "    const unsigned char* data;",
        "    size_t size;",
        "    const char* mime_type;",
        "};",
        ""
    ]
    
    # 生成资源数据
    resource_arrays = []
    resource_entries = []
    
    total_size = 0
    for file_path, route, final_route in files:
        try:
            with open(file_path, 'rb') as f:
                data = f.read()
            
            var_name, array_code, entry_code = generate_resource_entry(
                file_path, data, final_route
            )
            
            resource_arrays.append(array_code)
            resource_entries.append(entry_code)
            total_size += len(data)
            
            print(f"  {final_route} ({len(data):,} bytes)")
            
        except Exception as e:
            print(f"警告: 无法处理文件 {file_path}: {e}")
            continue
    
    # 添加资源数组到头文件
    header_lines.extend(resource_arrays)
    header_lines.append("")
    
    # 添加资源映射表
    header_lines.extend([
        "// 嵌入式Web资源映射表",
        "static const EmbeddedResource embedded_resources[] = {",
    ])
    
    for i, entry in enumerate(resource_entries):
        if i < len(resource_entries) - 1:
            header_lines.append(entry + ",")
        else:
            header_lines.append(entry)
    
    header_lines.extend([
        "};",
        "",
        f"static const size_t embedded_resources_count = {len(resource_entries)};",
        f"static const size_t total_embedded_size = {total_size};",
        "",
        "// 查找嵌入式资源",
        "inline const EmbeddedResource* find_resource(const std::string& path) {",
        "    for (size_t i = 0; i < embedded_resources_count; ++i) {",
        "        if (embedded_resources[i].path == path) {",
        "            return &embedded_resources[i];",
        "        }",
        "    }",
        "    return nullptr;",
        "}",
        "",
        "// 获取所有资源路径",
        "inline std::vector<std::string> get_all_resource_paths() {",
        "    std::vector<std::string> paths;",
        "    paths.reserve(embedded_resources_count);",
        "    for (size_t i = 0; i < embedded_resources_count; ++i) {",
        "        paths.emplace_back(embedded_resources[i].path);",
        "    }",
        "    return paths;",
        "}",
        "",
        "} // namespace web",
        "} // namespace ems",
        "",
        "#endif // EMBEDDED_WEB_RESOURCES_H"
    ])
    
    # 写入文件
    os.makedirs(os.path.dirname(output_file), exist_ok=True)
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write('\n'.join(header_lines))
    
    print(f"生成完成: {output_file}")
    print(f"总大小: {total_size:,} bytes ({total_size/1024:.1f} KB)")
    print(f"资源数量: {len(resource_entries)}")

def main():
    """主函数"""
    if len(sys.argv) != 3:
        print("用法: python3 embed-web-resources.py <web_directory> <output_header>")
        print("示例: python3 embed-web-resources.py ./build/web ./src/web/EmbeddedWebResources.h")
        sys.exit(1)
    
    web_directory = sys.argv[1]
    output_header = sys.argv[2]
    
    try:
        generate_header_file(web_directory, output_header)
    except Exception as e:
        print(f"错误: {e}")
        sys.exit(1)

if __name__ == '__main__':
    main()
